import { getLocalToken } from "@/utils/token";
// import { } from '@dcloudio/uni-app'

// 前置url
const baseUrl = import.meta.env.VITE_BASE_URL;
const tokenUrl = import.meta.env.VITE_LOGIN_URL;
const sseUrl = import.meta.env.VITE_SSE_BASE_URL;

/**
 * 请求前置函数
 * @param mode 请求的模式
 */
// XXX 这里使用了前置函数让所有请求都先确认token是否存在，没有则请求。但是写法感觉比较粗糙，后续可以优化
const beforeRequest = async (mode: string) => {
  try {

  } catch (err) {
    console.error('beforeRequest error', err)
  }
}

// 请求后置函数
const afterRequest = () => {
}

class MyRequest {
  constructor(baseUrl: string, tokenUrl: string, beforeRequest: Function, afterRequest: Function) {
    this.baseUrl = baseUrl;
    this.tokenUrl = tokenUrl;
    this.beforeRequest = beforeRequest;
    this.afterRequest = afterRequest;
  }

  baseUrl: string;
  tokenUrl: string;
  beforeRequest: Function;
  afterRequest: Function;

  /**
   * @description: 请求函数
   * @param {string} apiUrl 请求的api地址
   * @param {string} method 请求的方法
   * @param {object} data 请求的参数
   * @param {object} options 请求的其他参数
   * @param {string} mode 请求的模式，包括token、base，默认为base
   */
  async requestFunction(
    apiUrl: string,
    method: UniNamespace.RequestOptions['method'],
    data: AnyObject = {},
    options: AnyObject = {},
    mode: 'token' | 'base' = 'base'
  ) {
    // 根据模式选择url
    let url = '';
    switch (mode) {
      case 'token':
        url = this.tokenUrl + apiUrl;
        break;
      default:
        url = this.baseUrl + apiUrl;
    }

    try {
      await this.beforeRequest(mode);
    } catch (err) {
      console.error('beforeRequest error', err)
    }

    return new Promise((resolve, reject) => {
      uni.request({
        url,
        method,
        header: {
          'token': getLocalToken()
        },
        data,
        ...options,
        success: (res: any) => {
          if (res?.data?.message === '401') {
            uni.showToast({
              title: '登录已过期',
              icon: 'none'
            });
            return;
          }
          this.afterRequest();
          resolve(res);
        },
        fail: (err: any) => {
          this.afterRequest();
          uni.showToast({
            title: '网络错误',
            icon: 'error'
          });

          reject(err);
        }
      });
    })
  }

  /**
   * @description: get请求
   * @param {string} apiUrl 请求的api地址
   * @param {object} data 请求的参数，可选
   * @param {object} options 请求的其他参数，可选
   */
  get(apiUrl: string, data: AnyObject = {}, options: AnyObject = {}) {
    return this.requestFunction(apiUrl, 'GET', data, options);
  }

  /**
   * @description: 获取token
   * @param {string} apiUrl 请求的api地址
   * @param {object} data 请求的参数，可选
   * @param {object} options 请求的其他参数，可选
   */
  getAboutUser(apiUrl: string, data: AnyObject = {}, options: AnyObject = {}) {
    return this.requestFunction(apiUrl, 'GET', data, options, 'token');
  }

  /**
   * @description: post请求
   * @param {string} apiUrl 请求的api地址
   * @param {object} data 请求的参数，可选
   * @param {object} options 请求的其他参数，可选
   */
  post(apiUrl: string, data: AnyObject = {}, options: AnyObject = {}) {
    return this.requestFunction(apiUrl, 'POST', data, options);
  }
}

export default new MyRequest(baseUrl, tokenUrl, beforeRequest, afterRequest);

/**
 * 普通get请求
 * @param apiUrl 请求的api地址
 * @param data 请求的参数，可选
 * @param options 请求的其他参数，可选
 */
export const reqGet = async (apiUrl: string, data: AnyObject = {}, options: AnyObject = {}) => {
  await beforeRequest('base');

  try {
    const res = await uni.request({
      url: baseUrl + apiUrl,
      method: 'GET',
      header: {
        'token': getLocalToken()
      },
      data,
      ...options
    });
    return res;
  } catch (err) {
    console.error(`${apiUrl} get error`, err)
  } finally {
    afterRequest();
  }
}

/**
 * 用户相关的get请求
 * @param apiUrl 请求的api地址
 * @param data 请求的参数，可选
 * @param options 请求的其他参数，可选
 */
export const reqGetAboutUser = async (apiUrl: string, data: AnyObject = {}, options: AnyObject = {}) => {
  await beforeRequest('token');

  try {
    const res = await uni.request({
      url: tokenUrl + apiUrl,
      method: 'GET',
      header: {
        'token': getLocalToken()
      },
      data,
      ...options
    });
    return res;
  } catch (err) {
    console.error(`${apiUrl} get error`, err)
  } finally {
    afterRequest();
  }
}

/**
 * 普通post请求
 * @param apiUrl 请求的api地址
 * @param data 请求的参数，可选
 * @param options 请求的其他参数，可选
 */
export const reqPost = async (apiUrl: string, data: AnyObject = {}, options: AnyObject = {}) => {
  await beforeRequest('base');

  try {
    const res = await uni.request({
      url: baseUrl + apiUrl,
      method: 'POST',
      header: {
        'token': getLocalToken()
      },
      data,
      ...options
    });
    return res;
  } catch (err) {
    console.error(`${apiUrl} post error`, err)
  } finally {
    afterRequest();
  }
}

// 上传文件
export const reqUploadFile = async (apiUrl: string, filePath: string, data: AnyObject = {}, options: AnyObject = {}) => {
  await beforeRequest('token')

  try {
    const res: any = await new Promise((resolve, reject) => {
      uni.uploadFile({
        url: baseUrl + apiUrl,
        filePath,
        header: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'token': getLocalToken()
        },
        name: 'file',
        formData: {
          ...data,
          prefix: 'wechat-complaints'
        },
        ...options,
        success: (res: any) => { resolve(res) },
        fail: (err: any) => { throw err },
        complete: () => { afterRequest() }
      });
    });
    return res;
  } catch (err) {
    console.error(`${apiUrl} uploadFile error`, err)
  } finally {
    afterRequest();
  }
}


export const requestSSE = async (apiUrl: string, method: UniNamespace.RequestOptions['method'], data: AnyObject = {}, headerOther: AnyObject = {}, successHandler?: Function) => {
  let requestTask = {};
  await beforeRequest('token')
  try {
    const res: any = await new Promise((resolve, reject) => {
      requestTask = uni.request({
        url: sseUrl + apiUrl,
        method,
        header: {
          'token': getLocalToken() || '',
          ...headerOther
        },
        data,
        success: (res: any) => {
          if (successHandler) {
            successHandler(res)
          }
          resolve({requestTask, res})
        },
        fail: (err: any) => { throw err },
        complete: () => { afterRequest() }
      });
    });
    console.log('结果', res);
    
    return res;
  } catch (err) {
    console.error(`${apiUrl} uploadFile error`, err)
    return {
      requestTask,
      err
    }
  } finally {
    afterRequest();
  }
}
